package com.yzl.frelink.service.impl;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.yzl.frelink.entities.Fretish;
import com.yzl.frelink.entities.chart.Parameter;
import com.yzl.frelink.entities.chart.StateTree;
import com.yzl.frelink.entities.chart.StateTreeNode;
import com.yzl.frelink.entities.chart.Transition;
import com.yzl.frelink.entities.component.Chart;
import com.yzl.frelink.entities.component.Component;
import com.yzl.frelink.entities.component.Port;
import com.yzl.frelink.entities.dep.Demap;
import com.yzl.frelink.entities.model.Model;
import com.yzl.frelink.service.BuilderService;
import com.yzl.frelink.service.analyze.RegulationAnalyzer;
import com.yzl.frelink.service.analyze.TypeAnalyzer;
import com.yzl.frelink.service.build.ParameterBuilder;
import com.yzl.frelink.service.build.PortBuilder;
import com.yzl.frelink.service.build.StateBuilder;
import com.yzl.frelink.service.build.TransitionBuilder;
import com.yzl.frelink.service.matlab.DotCompiler;
import com.yzl.frelink.service.pattern.PatternBuilder;
@Service
public class BuilderServiceImpl implements BuilderService {
    @Autowired
    private StateBuilder stateBuilder;
    @Autowired
    private TransitionBuilder transitionBuilder;
    @Autowired
    private RegulationAnalyzer regulationAnalyzer;
    @Autowired
    private ParameterBuilder parameterBuilder;
    @Autowired
    private PortBuilder portBuilder;
    @Autowired
    private PatternBuilder patternBuilder;
    @Autowired
    private TypeAnalyzer typeAnalyzer;

    @Override
    public Model buildModel(String name) {
        Model model = new Model();
        if (name.contains("/")) {
            name = name.substring(name.lastIndexOf("/") + 1, name.lastIndexOf("."));
        } else if (name.contains("\\")) {
            name = name.substring(name.lastIndexOf("\\") + 1, name.lastIndexOf("."));
        }
        System.out.println("Building model: " + name);
        model.setName(name);
        return model;
    }

    @Override
    public Chart buildChart(Fretish[] requirements, Demap demap) {
        // todo 多个组件
        Chart chart = new Chart(requirements[0].getComponent());
        // 分析状态层级关系
        Map<String, List<Fretish>> modeToReqs = regulationAnalyzer.groupByMode(requirements);
        parameterBuilder.addParametersByDependency(chart, demap);
        typeAnalyzer.setParamsType(chart, requirements);
        chart.setStateTree(getStructure(chart, demap, modeToReqs));
        transitionBuilder.setUnsettedRearTrans(chart);
        return chart;
    }
    
    private StateTree getStructure(Chart chart, Demap demap, Map<String, List<Fretish>> modeToReqs) {
        StateTree stateTree = new StateTree();
        Deque<StateTreeNode> queue = new ArrayDeque<>(); // 遍历队列
        stateBuilder.generateEntryStates(chart, demap, queue, stateTree);

        while (!queue.isEmpty()) {
            StateTreeNode current = queue.pollFirst();
            List<StateTreeNode> generatedStates = stateBuilder.generateSubStates(current, chart, demap, modeToReqs);
            queue.addAll(generatedStates);
        }
        // System.out.println(stateTree);
        stateBuilder.checkAndDelOverall(stateTree, chart, demap);
        return stateTree;
    }

    public void setModelPosition(Model model) {
        DotCompiler.setModelPosition(model);
    }

    @Override
    public void buildPortsAndLines(Model model) {
        portBuilder.buildPortsAndLines(model);
    }

    @Override
    public void addTimers(Model model, Fretish[] requirements) {
        String timerRegex = "[^_]+_timer";
        Pattern pattern = Pattern.compile(timerRegex);
        Set<String> timerNames = new HashSet<>();
        for (Fretish req : requirements) {
            for (String var : req.getOutVars()) {
                Matcher matcher = pattern.matcher(var);
                if (matcher.find()) {
                    timerNames.add(matcher.group(0));
                }
            }
        }
        for (String name : timerNames) {
            model.addChart(patternBuilder.buildTimer(name));
        }
    }
}
